package db

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"reflect"
	"strings"

	"loghub/common"
	"loghub/model"
)

// QueryScalarFloat64 查询单个值, 比如Count(*), Sum函数等 int64也会自动成为float64
func QueryScalarFloat64(sql string) (scalarValue float64, orginalValue interface{}, errmsg error) {
	sql = strings.ReplaceAll(sql, "\n", " ")
	sql = strings.ReplaceAll(sql, "\t", " ")

	var requestBody = `[ "` + sql + `" ]`
	var url = "http://localhost:4001/db/query?pretty&timings"
	request, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(requestBody)))
	if err != nil {
		log.Println("数据库初始化http请求失败", err)
		return 0, nil, err
	}

	request.Header.Set("Content-Type", "application/json")
	client := &http.Client{}

	resp, err := client.Do(request)
	if err != nil {
		log.Println("rqlite服务报错", err)
		return 0, nil, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("读取响应数据失败", err)
		return 0, nil, err
	}

	var queryResult model.QueryResult
	err = json.Unmarshal(body, &queryResult)
	if err != nil {
		log.Println("解析json结果失败", err)
		return 0, nil, err
	}

	// log.Println(queryResult.Results[0].Columns)
	// log.Println(queryResult.Results[0].Types)
	var queryValue = queryResult.Results[0].Values[0]
	if value, ok := queryValue.([]interface{}); ok {
		// log.Println(value[0])
		// log.Println(reflect.TypeOf(value[0]))
		if count, ok := value[0].(float64); ok {
			return count, count, nil
		}
		return 0, value[0], errors.New("value[0]未知的返回值类型,请考虑手动进行类型转换")
	}

	return 0, queryValue, errors.New("queryValue是未知的返回值类型,请考虑手动进行类型转换")
}

// QueryStructByReflect 是利用反射获取值, exexResult 参数必须是结构体的指针
func QueryStructByReflect(sql string, structPtr interface{}) (errmsg error) {
	var paramType = reflect.TypeOf(structPtr)
	if paramType.Kind() != reflect.Ptr {
		return errors.New("structPtr 参数必须是结构体的指针类型")
	}

	sql = strings.ReplaceAll(sql, "\n", " ")
	sql = strings.ReplaceAll(sql, "\t", " ")

	var requestBody = `[ "` + sql + `" ]`
	var url = "http://localhost:4001/db/query?pretty&timings"
	request, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(requestBody)))
	if err != nil {
		log.Println("数据库初始化http请求失败", err)
		return err
	}

	request.Header.Set("Content-Type", "application/json")
	client := &http.Client{}

	resp, err := client.Do(request)
	if err != nil {
		log.Println("rqlite服务报错", err)
		return err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("读取响应数据失败", err)
		return err
	}

	var queryResult model.QueryResult
	err = json.Unmarshal(body, &queryResult)
	if err != nil {
		log.Println("解析json结果失败", err)
		return err
	}

	// log.Println(queryResult.Results[0].Columns)
	// log.Println(queryResult.Results[0].Types)
	if len(queryResult.Results) == 0 {
		log.Println("queryResult.Results 长度为0, 查询获取0条记录, 请检查sql是否拼写错误")
		return errors.New("queryResult.Results 长度为0, 查询获取0条记录, 请检查sql是否拼写错误")
	}

	var columns = queryResult.Results[0].Columns
	if queryResult.Results != nil && len(queryResult.Results) > 0 && queryResult.Results[0].Values != nil && len(queryResult.Results[0].Values) > 0 {
		var queryValue = queryResult.Results[0].Values[0]

		if valSlice, ok := queryValue.([]interface{}); ok {
			if len(columns) == len(valSlice) {
				var jsonMaps = make(map[string]interface{})
				for ix, v := range columns {
					jsonMaps[v] = valSlice[ix]
				}
				common.SetStructFieldByJSONName(structPtr, jsonMaps)
			}
		}
	}

	// fmt.Println(columns)
	// fmt.Println(queryValue)

	return nil
}

// QueryStructListByReflect 查询多条记录
func QueryStructListByReflect(sql string, valueType reflect.Type) (values []interface{}, errmsg error) {
	if reflect.TypeOf(valueType).Elem().Kind() != reflect.Struct {
		log.Println(reflect.TypeOf(valueType).Kind())
		return nil, errors.New("valueType 必须是结构体类型的变量")
	}

	sql = strings.ReplaceAll(sql, "\n", " ")
	sql = strings.ReplaceAll(sql, "\t", " ")

	var requestBody = `[ "` + sql + `" ]`
	var url = "http://localhost:4001/db/query?pretty&timings"
	request, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(requestBody)))
	if err != nil {
		log.Println("数据库初始化http请求失败", err)
		return nil, err
	}

	request.Header.Set("Content-Type", "application/json")
	client := &http.Client{}

	resp, err := client.Do(request)
	if err != nil {
		log.Println("rqlite服务报错", err)
		return nil, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("读取响应数据失败", err)
		return nil, err
	}

	var queryResult model.QueryResult
	err = json.Unmarshal(body, &queryResult)
	if err != nil {
		log.Println("解析json结果失败", err)
		return nil, err
	}

	// log.Println(queryResult.Results[0].Columns)
	// log.Println(queryResult.Results[0].Types)
	if len(queryResult.Results) == 0 {
		log.Println("queryResult.Results 长度为0, 查询获取0条记录, 请检查sql是否拼写错误")
		return nil, errors.New("queryResult.Results 长度为0, 查询获取0条记录, 请检查sql是否拼写错误")
	}

	var columns = queryResult.Results[0].Columns
	if queryResult.Results != nil && len(queryResult.Results) > 0 && queryResult.Results[0].Values != nil && len(queryResult.Results[0].Values) > 0 {
		// 将多条记录查询出来然后动态创建结构体切片
		if len(queryResult.Results[0].Values) > 0 {
			var slice = make([]interface{}, 0)
			for _, v := range queryResult.Results[0].Values {
				if valSlice, ok := v.([]interface{}); ok {
					if len(columns) == len(valSlice) {
						var jsonMaps = make(map[string]interface{})
						for ix, v := range columns {
							jsonMaps[v] = valSlice[ix]
						}
						// new 一个当前结构体的实例, 返回指针地址
						var value = reflect.New(valueType).Interface()
						if reflect.TypeOf(value).Kind() == reflect.Ptr {
							common.SetStructFieldByJSONName(value, jsonMaps)
							slice = append(slice, reflect.ValueOf(value).Elem().Interface())
						}
					}
				}
			}
			return slice, nil
		}
	}

	return nil, errors.New("QueryStructListByReflect 查无结果,sql: " + sql)
}

// ExecSQL 是执行ddl或者dml语句的返回结果, 报错返回error
func ExecSQL(sql string) (execResult interface{}, errmsg error) {
	sql = strings.ReplaceAll(sql, "\n", " ")
	sql = strings.ReplaceAll(sql, "\t", " ")
	var requestBody = `[ "` + sql + `" ]`
	var url = "http://localhost:4001/db/execute?pretty&timings"
	request, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(requestBody)))
	if err != nil {
		log.Println("数据库初始化http请求失败", err)
		return nil, err
	}

	request.Header.Set("Content-Type", "application/json")
	client := &http.Client{}

	resp, err := client.Do(request)
	if err != nil {
		log.Println("rqlite服务报错", err)
		return nil, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("读取响应数据失败", err)
		return nil, err
	}

	var result model.ExecResult
	err = json.Unmarshal(body, &result)
	if err != nil {
		log.Println("解析json结果失败", string(body))
		return nil, err
	}

	var queryValue = result.Results[0]

	if maps, ok := queryValue.(map[string]interface{}); ok {
		if errString, ok := maps["error"]; ok {
			log.Println(errString)
			return nil, errors.New(errString.(string))
		}
		// log.Println(maps)
	}
	return queryValue, nil
}
